package com.qijian.mold.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.SecurityUtils;
import com.qijian.mold.domain.dto.*;
import com.qijian.mold.domain.entity.Mold;
import com.qijian.mold.domain.entity.MoldChange;
import com.qijian.mold.domain.entity.MoldChangeTask;
import com.qijian.mold.domain.entity.TaskUserMp;
import com.qijian.mold.domain.param.mold.GetEqpParam;
import com.qijian.mold.domain.param.mold.GetMoldChangeListByCurrentIdParam;
import com.qijian.mold.domain.param.mold.GetUserDetailByRoleTypeParam;
import com.qijian.mold.domain.param.mold.GetWorkOrderDetailsListParam;
import com.qijian.mold.domain.param.moldChange.*;
import com.qijian.mold.domain.param.task.CompleteMoldChangeParam;
import com.qijian.mold.domain.vo.moldChange.*;
import com.qijian.mold.domain.vo.moldChangeLog.ChangeLogListVo;
import com.qijian.mold.domain.vo.user.UserDetailsVo;
import com.qijian.mold.enums.*;
import com.qijian.mold.repository.MoldChangeRepository;
import com.qijian.mold.repository.MoldChangeTaskRepository;
import com.qijian.mold.repository.MoldRepository;
import com.qijian.mold.service.MoldChangeLogService;
import com.qijian.mold.service.MoldChangeService;
import com.qijian.mold.util.IdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 换模信息
 *
 * @author anni.zhu
 * @author anni.zhu@king-v.com
 * Created in 2025/3/29 17:25
 */
@Service
public class MoldChangeServiceImpl implements MoldChangeService {

    @Autowired
    private MoldChangeRepository changeRepository;
    @Autowired
    private MoldChangeLogService logService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private MoldRepository moldRepository;
    @Autowired
    private MoldChangeTaskRepository taskRepository;

    /**
     * 新增换模信息
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(CreateMoldChangeParam param) {
        //从token拿到获取当前用户信息
        Long userId = SecurityUtils.getLoginUser().getUserId();

        //如果设备有进行中的换模申请不能再创建新的换模申请
        List<MoldChange> moldChanges = changeRepository.getBaseMapper().selectList(new LambdaQueryWrapper<MoldChange>()
                .eq(MoldChange::getStatus, MoldChangeStatusEnum.IN_PROGRESS.getId())
                .eq(MoldChange::getEqpId, param.getEqpId())
                .eq(MoldChange::getIsDel, 0)
        );
        if (CollectionUtil.isNotEmpty(moldChanges)) {
            throw new ServiceException("有进行中的换模申请不能再创建新的换模申请");
        }

        MoldChange moldChange = new MoldChange();
        BeanUtils.copyProperties(param, moldChange);
        moldChange.setCreateUserId(userId);

        //根据设备id获取设备信息
        EqpVo eqpDetail = changeRepository.getEqpDetail(param.getEqpId());
        if (eqpDetail == null) {
            throw new ServiceException("设备不存在");
        }
        BeanUtils.copyProperties(eqpDetail, moldChange);

        //根据工序单id获取工序信息
        WorkOrderDetailsVo vo = changeRepository.getWorkOrderDetails(param.getWorkOrderDetailId());
        if (vo == null) {
            throw new ServiceException("工序单不存在");
        }
        BeanUtils.copyProperties(vo, moldChange);
        moldChange.setId(IdGenerator.SNOW.generate());
        //获取编号
        String code = getCode();
        moldChange.setCode(code);

        moldChange.setWorkshopApplyTime(LocalDateTime.now());
        moldChange.setType(MoldChangeLogTypesEnum.TECHNICAL_CONFIRM.getId());
        moldChange.setTypeStatus(MoldChangeStatusEnum.IN_PROGRESS.getId());
        moldChange.setStatus(MoldChangeStatusEnum.IN_PROGRESS.getId());
        moldChange.setDetailsType(MoldChangeLogDetailsTypesEnum.DEFAULT.getId());
        if (!changeRepository.save(moldChange)) {
            throw new ServiceException("新增换模信息失败");
        }

        //新增车间申请日志
        logService.saveChangeLog(moldChange.getId(), moldChange.getCreateUserId(), MoldChangeLogTypesEnum.WORKSHOP_APPLY, null, Collections.EMPTY_LIST);

    }

    /**
     * 根据设备id获取设备信息
     *
     * @param eqpId
     * @return
     */
    @Override
    public EqpVo getEqpById(Long eqpId) {
        EqpVo eqpDetail = changeRepository.getEqpDetail(eqpId);
        if (eqpDetail != null) {
            //根据设备id获取进行中的申请单id
            List<MoldChange> moldChangeList = changeRepository.getBaseMapper().selectList(
                    new LambdaQueryWrapper<MoldChange>()
                            .eq(MoldChange::getEqpId, eqpId)
                            .eq(MoldChange::getStatus, MoldChangeStatusEnum.IN_PROGRESS.getId())
                            .eq(MoldChange::getIsDel, 0)
            );
            if (CollectionUtil.isNotEmpty(moldChangeList)) {
                eqpDetail.setMoldChangeId(moldChangeList.get(0).getId());
            }
        }
        return eqpDetail;
    }

    /**
     * 根据设备code获取设备信息
     * @param code
     * @return
     */
    @Override
    public EqpVo getEqpByCode(String code) {
        EqpVo eqpDetail = changeRepository.getEqpByCode(code);
        if (eqpDetail != null) {
            //根据设备id获取进行中的申请单id
            List<MoldChange> moldChangeList = changeRepository.getBaseMapper().selectList(
                    new LambdaQueryWrapper<MoldChange>()
                            .eq(MoldChange::getEqpId, eqpDetail.getEqpId())
                            .eq(MoldChange::getStatus, MoldChangeStatusEnum.IN_PROGRESS.getId())
                            .eq(MoldChange::getIsDel, 0)
            );
            if (CollectionUtil.isNotEmpty(moldChangeList)) {
                eqpDetail.setMoldChangeId(moldChangeList.get(0).getId());
            }
        }
        return eqpDetail;
    }

    /**
     * 获取设备列表
     * 如果不校验数据，那就是所有不在进行中的申请单的设备id
     * 如果校验数据，那就是需要显示进行中的换模申请单的设备ids
     * @return
     */
    @Override
    public Page<EqpVo> getEqpList(GetEqpParam param) {
        GetEqpDto dto=new GetEqpDto();
        BeanUtils.copyProperties(param,dto);
        Page<EqpVo> page = changeRepository.getEqpList(dto);
        if (CollectionUtil.isNotEmpty(page.getRecords())) {
            if (param.getIsCheck()!=null && param.getIsCheck()) {
                for (EqpVo eqpVo : page.getRecords()) {
                    //根据设备id获取进行中的申请单id
                    List<MoldChange> moldChangeList = changeRepository.getBaseMapper().selectList(
                            new LambdaQueryWrapper<MoldChange>()
                                    .eq(MoldChange::getEqpId, eqpVo.getEqpId())
                                    .eq(MoldChange::getStatus, MoldChangeStatusEnum.IN_PROGRESS.getId())
                                    .eq(MoldChange::getIsDel, 0)
                    );
                    if (CollectionUtil.isNotEmpty(moldChangeList)) {
                        eqpVo.setMoldChangeId(moldChangeList.get(0).getId());
                    }
                }
            }
        }
        return page;
    }

    /**
     * 获取工单列表
     * 需要扣除换膜申请单里面的工单
     *
     * @return
     */
    @Override
    public Page<WorkOrderDetailsVo> getWorkOrderDetailsList(GetWorkOrderDetailsListParam param ) {
        GetWorkOrderDetailsListDto dto=new GetWorkOrderDetailsListDto();
        BeanUtils.copyProperties(param,dto);
        //获取当前用户
        Long userId = SecurityUtils.getLoginUser().getUserId();
        dto.setUserId(userId);
        return changeRepository.getWorkOrderDetailsList(dto);
    }

    /**
     * 生成编号：HMSL+年月日+数量（补齐三位）
     *
     * @return
     */
    private String getCode() {
        HashOperations<String, String, String> hash = stringRedisTemplate.opsForHash();
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Long value = changeRepository.getBaseMapper().selectCount(new LambdaQueryWrapper<MoldChange>()
                .like(MoldChange::getCreateTime, sdf.format(now)));

        sdf = new SimpleDateFormat("yyyyMMdd");
        String leftCode = "HMSL" + sdf.format(now);
        String rightCode = String.format("%03d", (value + 1));
        String code = leftCode + rightCode;
        while (!hash.putIfAbsent("ProcurementPlan", code, code)) {
            //前12位是固定的，后三位是数量，不足三位补0
            rightCode = code.substring(13);
            int number = Integer.valueOf(rightCode);
            rightCode = String.format("%03d", (number + 1));
            code = leftCode + rightCode;
        }
        return code;
    }

    /**
     * 查看换模信息详情
     *
     * @param id
     * @return
     */
    @Override
    public MoldChangeVo getById(Long id) {
        MoldChange moldChange = changeRepository.getById(id);
        if (moldChange == null) {
            throw new ServiceException("换模信息不存在");
        }
        MoldChangeVo moldChangeVo = new MoldChangeVo();
        BeanUtils.copyProperties(moldChange, moldChangeVo);

        //日志进展信息
        List<ChangeLogListVo> changeLogList = logService.getChangeLogList(id);
        moldChangeVo.setChangeLogList(changeLogList);

        //当前设备关联的所有模具名称
        List<Mold> molds = moldRepository.selectMoldListByEqpId(moldChange.getEqpId());
        List<String> moldNames = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(molds)) {
            moldNames = molds.stream().map(Mold::getName).distinct().toList();
        }
        moldChangeVo.setMoldNames(moldNames);

        //查询最近一次未完成的上模任务id
        MoldChangeTask upTask = getOneByChangeIdAndType(moldChange.getId(), MoldChangeTaskTypeEnum.UP);
        if (upTask != null) {
            moldChangeVo.setUpTaskId(upTask.getId());
        }
        //查询最近一次未完成的下模任务id
        MoldChangeTask downTask = getOneByChangeIdAndType(moldChange.getId(), MoldChangeTaskTypeEnum.DOWN);
        if (downTask != null) {
            moldChangeVo.setDownTaskId(downTask.getId());
        }

        //检查用户是否是车间操作员
        Boolean isWorkshopOperator = changeRepository.getMoleRoleByUserId(SecurityUtils.getLoginUser().getUserId(), MoldRoleEnum.WORKSHOP_OPERATOR.getName());
        //检查用户是否是技术部操作员
        Boolean isTechnician = changeRepository.getMoleRoleByUserId(SecurityUtils.getLoginUser().getUserId(), MoldRoleEnum.TECHNICIAN.getName());
        //检查用户是否操作工
        Boolean isWorker = changeRepository.getMoleRoleByUserId(SecurityUtils.getLoginUser().getUserId(), MoldRoleEnum.WORKER.getName());

        moldChangeVo.setIsWorkshopOperator(isWorkshopOperator);
        moldChangeVo.setIsTechnician(isTechnician);
        moldChangeVo.setIsWorker(isWorker);
        return moldChangeVo;
    }


    /**
     * 获取最近一次未完成的上下模任务id
     *
     * @param moldChangeId
     * @param type
     * @return
     */
    MoldChangeTask getOneByChangeIdAndType(Long moldChangeId, MoldChangeTaskTypeEnum type) {
        List<MoldChangeTask> moldChangeTasks = taskRepository.getBaseMapper().selectList(new LambdaQueryWrapper<MoldChangeTask>()
                .eq(MoldChangeTask::getMoldChangeId, moldChangeId)
                .eq(MoldChangeTask::getType, type.getId())
                .eq(MoldChangeTask::getStatus, MoldChangeStatusEnum.IN_PROGRESS.getId())
                .eq(MoldChangeTask::getIsDel, 0)
        );
        if (CollectionUtil.isNotEmpty(moldChangeTasks)) {
            return moldChangeTasks.get(0);
        } else {
            return null;
        }
    }

    /**
     * 获取换模信息分页列表
     *
     * @param param
     * @return
     */
    @Override
    public Page<MoldChangeListVo> selectByPage(SelectMoldChangeParam param) {
        SelectMoldChangeDto dto = new SelectMoldChangeDto();
        BeanUtils.copyProperties(param, dto);
        Long userId = SecurityUtils.getLoginUser().getUserId();

        //检查用户是否是admin账户
        Boolean isAdmin = changeRepository.getMoleRoleByUserId(SecurityUtils.getLoginUser().getUserId(), MoldRoleEnum.ADMIN.getName());
        //检查用户是否是车间操作员
        Boolean isWorkshopOperator = changeRepository.getMoleRoleByUserId(SecurityUtils.getLoginUser().getUserId(), MoldRoleEnum.WORKSHOP_OPERATOR.getName());
        //检查用户是否是技术部操作员
        Boolean isTechnician = changeRepository.getMoleRoleByUserId(SecurityUtils.getLoginUser().getUserId(), MoldRoleEnum.TECHNICIAN.getName());
        //检查用户是否操作工
        Boolean isWorker = changeRepository.getMoleRoleByUserId(SecurityUtils.getLoginUser().getUserId(), MoldRoleEnum.WORKER.getName());

        if (param.getIsCheck()){
            dto.setIsAdmin(isAdmin);
            dto.setIsWorkshopOperator(isWorkshopOperator);
            dto.setIsTechnician(isTechnician);
            dto.setIsWorker(isWorker);
            dto.setUserId(userId);
        }

        Page<MoldChangeListVo> page = changeRepository.getByPage(dto);
        page.getRecords().forEach(moldChangeListVo -> {
            moldChangeListVo.setIsWorkshopOperator(isWorkshopOperator);
            moldChangeListVo.setIsTechnician(isTechnician);
            moldChangeListVo.setIsWorker(isWorker);
        });
        return page;
    }

    /**
     * 技术部确认
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void departmentConfirm(ConfirmMoldChangParam param) {
        MoldChange moldChange = changeRepository.getById(param.getMoldChangeId());
        if (moldChange == null) {
            throw new ServiceException("换模信息不存在");
        }

        Long userId = SecurityUtils.getLoginUser().getUserId();
        //检查权限
        checkRole(userId, MoldRoleEnum.TECHNICIAN);

        moldChange.setTechConfirmTime(LocalDateTime.now());
        String ids = JSONArray.toJSONString(param.getConfirmUserIds());
        moldChange.setTechConfirmUserIds(ids);
        moldChange.setType(MoldChangeLogTypesEnum.MOLD_CHANGE_DEBUG.getId());
        moldChange.setTypeStatus(MoldChangeStatusEnum.IN_PROGRESS.getId());

        //可见人ids=选择得用户
        moldChange.setVisibleUserIds(ids);

        if (!changeRepository.updateById(moldChange)) {
            throw new ServiceException("技术部确认失败");
        }

        //新增技术部确认日志
        logService.saveChangeLog(moldChange.getId(), userId, MoldChangeLogTypesEnum.TECHNICAL_CONFIRM, null, param.getConfirmUserIds());
    }

    /**
     * 根据当前用户获取换模申请单数据
     * 如果是admin查询全部，状态为进行中并且阶段是换模调试的数据
     * 如果不是admin的话，查询当前用户的换模申请单，状态为阶段是换模调试的数据
     * @param
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Page<MoldChangeDownVo> getMoldChangeList(GetMoldChangeListByCurrentIdParam param) {
        //获取当前用户
        Long userId = SecurityUtils.getLoginUser().getUserId();

        GetMoldChangeListByCurrentIdDto dto=new GetMoldChangeListByCurrentIdDto();
        BeanUtils.copyProperties(param,dto);
        dto.setStatus(MoldChangeStatusEnum.IN_PROGRESS.getId());
        dto.setType(MoldChangeLogTypesEnum.MOLD_CHANGE_DEBUG.getId());

        //判断如果不是超管的话，只能看到自己的换模申请单
        Boolean isAdmin = changeRepository.getMoleRoleByUserId(userId, MoldRoleEnum.ADMIN.getName());
        if (!isAdmin) {
            dto.setUserId(userId);
        }

        Page<MoldChangeDownVo> page=changeRepository.getMoldChangeListByCurrentId(dto);
        return page;
    }


    /**
     * 换模申请的开始换模调试完成
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moldChangeOverDebug(CompleteMoldChangeParam param) {
        //获取当前用户
        Long userId = SecurityUtils.getLoginUser().getUserId();

        MoldChange moldChange = changeRepository.getById(param.getMoldChangeId());
        if (moldChange == null) {
            throw new ServiceException("换模信息不存在");
        }

        List<MoldChangeTask> moldChangeTasks = checkTask(moldChange.getId());
        if (CollectionUtil.isNotEmpty(moldChangeTasks)) {
            throw new ServiceException("有进行中的任务不能进行换模申请的开始换模调试完成");
        }

        moldChange.setDetailsType(MoldChangeLogDetailsTypesEnum.OVER_COMPLETE.getId());
        moldChange.setDebugConfirmUserId(userId);
        moldChange.setDebugConfirmTime(LocalDateTime.now());

        //进展变成进行中的车间确认
        moldChange.setTypeStatus(MoldChangeStatusEnum.IN_PROGRESS.getId());
        moldChange.setType(MoldChangeLogTypesEnum.WORKSHOP_CONFIRM.getId());

        List<Long> visibleUserIds = new ArrayList<>();
        visibleUserIds.add(userId);

        moldChange.setVisibleUserIds(JSONArray.toJSONString(visibleUserIds));
        if (!changeRepository.updateById(moldChange)) {
            throw new ServiceException("换模调试完成失败");
        }

        //新增日志
        logService.saveChangeLog(moldChange.getId(), userId, MoldChangeLogTypesEnum.MOLD_CHANGE_DEBUG, MoldChangeLogDetailsTypesEnum.OVER_COMPLETE, visibleUserIds);
    }

    /**
     * 获取进行中的换模任务
     *
     * @param moldChangeId
     * @return
     */
    List<MoldChangeTask> checkTask(Long moldChangeId) {
        List<MoldChangeTask> moldChangeTasks = taskRepository.getBaseMapper().selectList(new LambdaQueryWrapper<MoldChangeTask>()
                .eq(MoldChangeTask::getMoldChangeId, moldChangeId)
                .eq(MoldChangeTask::getStatus, MoldChangeStatusEnum.IN_PROGRESS.getId())
                .eq(MoldChangeTask::getIsDel, 0)
        );
        return moldChangeTasks;
    }

    /**
     * 检查权限
     *
     * @param userId
     * @param role
     */
    void checkRole(Long userId, MoldRoleEnum role) {
        //检查是否admin角色
        Boolean isAdmin = changeRepository.getMoleRoleByUserId(userId, MoldRoleEnum.ADMIN.getName());
        if (!isAdmin) {
            //检查该用户是是操作员并且符合该工段
            Boolean isOperator = changeRepository.getMoleRoleByUserId(userId, role.getName());
            if (!isOperator) {
                throw new ServiceException("您没有权限操作该设备,只有角色是" + role.getCommit() + "的用户才能操作");
            }
        }
    }

    /**
     * 车间确认
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void workshopConfirm(WorkshopConfirmMoldChangParam param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        //检查权限
        checkRole(userId, MoldRoleEnum.WORKSHOP_OPERATOR);

        MoldChange moldChange = changeRepository.getById(param.getMoldChangeId());
        if (moldChange == null) {
            throw new ServiceException("换模信息不存在");
        }
        if (moldChange.getType() != MoldChangeLogTypesEnum.WORKSHOP_CONFIRM.getId()) {
            throw new ServiceException("只有开始换模调试阶段完成之后才能进行车间确认");
        }

        List<MoldChangeTask> moldChangeTasks = checkTask(moldChange.getId());
        if (CollectionUtil.isNotEmpty(moldChangeTasks)) {
            throw new ServiceException("有进行中的任务不能进行车间确认");
        }

        moldChange.setFinishTime(LocalDateTime.now());
        moldChange.setWorkshopConfirmUserId(param.getConfirmUserId());
        moldChange.setType(MoldChangeLogTypesEnum.WORKSHOP_CONFIRM.getId());
        moldChange.setTypeStatus(MoldChangeStatusEnum.COMPLETED.getId());
        //单据扭转为已完成
        moldChange.setStatus(MoldChangeStatusEnum.COMPLETED.getId());
        List<Long> confirmUserIds = new ArrayList<>();
        confirmUserIds.add(param.getConfirmUserId());

        moldChange.setVisibleUserIds(JSONArray.toJSONString(confirmUserIds));
        if (!changeRepository.updateById(moldChange)) {
            throw new ServiceException("车间确认失败");
        }

        //新增车间确认日志
        logService.saveChangeLog(moldChange.getId(), userId, MoldChangeLogTypesEnum.WORKSHOP_CONFIRM, null, confirmUserIds);
    }

    /**
     * 根据角色类型获取用户 1-技术员 2-车间操作员 3-操作员
     *
     * @param param
     * @return
     */
    @Override
    public Page<UserDetailsVo> getUserDetailByRoleType(GetUserDetailByRoleTypeParam param) {
        Integer roleType = param.getRoleType();
        Long eqpId = param.getEqpId();

        GetUserDetailsByRoleTypeDto dto=new GetUserDetailsByRoleTypeDto();
        String roleKey = MoldRoleEnum.getNameById(roleType);
        BeanUtils.copyProperties(param,dto);
        dto.setRoleKey(roleKey);

        Page<UserDetailsVo> userByRoleKey = changeRepository.getUserByRoleKey(dto);
        //如果是操作员检查是否有该工段
        if (roleType == 3) {
            if (eqpId == null) {
                throw new ServiceException("操作员需要传递设备id");
            }
            EqpVo eqpDetail = changeRepository.getEqpDetail(eqpId);
            if (eqpDetail != null) {
                if (eqpDetail.getLocationId() == null) {
                    throw new ServiceException("设备没有工段信息，请联系管理员");
                }
                dto.setLocationId(eqpDetail.getLocationId());
                Page<UserDetailsVo> operatorByRoleKey = changeRepository.getOperatorByRoleKey(dto);
                if (CollectionUtil.isEmpty(operatorByRoleKey.getRecords())) {
                    throw new ServiceException("没有该工段的操作员，请联系管理员");
                }
                return operatorByRoleKey;
            }
        }
        return userByRoleKey;
    }

    @Override
    public void updateMoldVisibleUserIds(UpdateMoldVisibleUserIdsParam param) {
        MoldChange moldChange = changeRepository.getById(param.getMoldChangeId());
        if (moldChange == null) {
            throw new ServiceException("换模信息不存在");
        }
        moldChange.setVisibleUserIds(JSONArray.toJSONString(param.getVisibleUserIds()));
        if (!changeRepository.updateById(moldChange)) {
            throw new ServiceException("修改可见人ids失败");
        }
    }


}
